package com.fhs.easycloud.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fhs.easycloud.anno.CloudApi;
import com.fhs.easycloud.anno.CloudMethod;
import com.fhs.easycloud.util.ParamChecker;
import com.fhs.easycloud.util.ReflectUtils;
import com.fhs.easycloud.util.SpringContextUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * 用来代理
 */
@Slf4j
@RestController
@RequestMapping("/easyCloud/proxy")
public class EasyCloudApiController {
    /**
     * 执行RPC方法
     *
     * @param serviceClass 方法类
     * @param methodName   方法名
     * @param request      req
     * @param response     res
     */
    @PostMapping("/{serviceClass}/{methodName}")
    public Object doExec(@PathVariable("serviceClass") String serviceClass, @PathVariable("methodName") String methodName, HttpServletRequest request, HttpServletResponse response) {
        ParamChecker.isNotNullOrEmpty(serviceClass, "serviceClass 不可为空");
        ParamChecker.isNotNullOrEmpty(methodName, "methodName 不可为空");
        try {
            Class clazz = Class.forName(serviceClass);
            if (!clazz.isAnnotationPresent(CloudApi.class)) {
                throw new RuntimeException("调用接口没有标记CloudApi");
            }
            Method method = ReflectUtils.getMethodd(clazz, methodName);
            if (method == null) {
                throw new RuntimeException("方法不存在");
            }
            if (!method.isAnnotationPresent(CloudMethod.class)) {
                throw new RuntimeException("方法没有标记CloudMethod");
            }
            Object service = SpringContextUtil.getBeanByClassForApi(clazz);
            clazz = SpringContextUtil.getTarget(service).getClass();
            method = ReflectUtils.getMethodd(clazz, methodName);
            String jsonString = readAsChars(request);
            Object[] params = new Object[method.getParameterTypes().length];
            Type[] types = method.getGenericParameterTypes();
            JSONObject paramMap = JSONObject.parseObject(jsonString);
            for (int i = 0; i < params.length; i++) {
                params[i] = parseJson(types[i], method.getParameterTypes()[i], i, paramMap);
            }

            try {
                Object result = method.invoke(service, params);
                return result;
            } catch (IllegalAccessException e) {
                log.error("", e);
            } catch (InvocationTargetException e) {
                log.error("", e);
            }
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("serviceClass 名称错误");
        }
        return null;
    }

    /**
     * 将参数json转换为object
     * @param type 类型
     * @param clazz class
     * @param index 第几个参数
     * @param paramMap 大参数集合
     * @return
     */
    private Object parseJson(Type type, Class<?> clazz, int index, JSONObject paramMap) {
        String key = index + "";
        if (Collection.class.isAssignableFrom(clazz)) {
            JSONArray tempParam = paramMap.getJSONArray(key);
            Type xxType = ((ParameterizedType) type).getActualTypeArguments()[0];
            return JSONObject.parseArray(tempParam.toJSONString(), (Class) xxType);
        }
        if (clazz.isArray()) {
            JSONArray tempParam = paramMap.getJSONArray(key);
            List<?> list = JSONObject.parseArray(tempParam.toJSONString(), clazz.getComponentType());
            Object array = Array.newInstance(clazz.getComponentType(), list.size());
            return list.toArray((Object[]) array);
        }

        if(Integer.class.equals(clazz)){
            return paramMap.getInteger(key);
        }
        if(Long.class.equals(clazz)){
            return paramMap.getLong(key);
        }
        if(Date.class.equals(clazz)){
            return paramMap.getDate(key);
        }
        if(String.class.equals(clazz)){
            return paramMap.getString(key);
        }
        if(Short.class.equals(clazz)){
            return paramMap.getShort(key);
        }
        if(Byte.class.equals(clazz)){
            return paramMap.getByte(key);
        }
        if(BigDecimal.class.equals(clazz)){
            return paramMap.getBigDecimal(key);
        }
        if(Double.class.equals(clazz)){
            return paramMap.getDouble(key);
        }
        if(Boolean.class.equals(clazz)){
            return paramMap.getBoolean(key);
        }
        JSONObject tempParam = paramMap.getJSONObject(key);
        return JSONObject.parseObject(tempParam.toJSONString(), type);
    }

    /**
     * 从request中读取body
     *
     * @param request request
     * @return body json
     */
    public String readAsChars(HttpServletRequest request) {

        BufferedReader br = null;
        StringBuilder sb = new StringBuilder("");
        try {
            br = request.getReader();
            String str;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            br.close();
        } catch (IOException e) {
            log.error("", e);
        } finally {
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    log.error("", e);
                }
            }
        }
        return sb.toString();
    }

    private List<Date> list;

    public static void hello(List<Integer> list) {

    }

    public static void main(String[] args) throws SecurityException, NoSuchFieldException, NoSuchMethodException {

        //方法入参泛型类型
        Method m = EasyCloudApiController.class.getMethod("hello", List.class);
        Type[] types = m.getGenericParameterTypes();
        ParameterizedType ptt = (ParameterizedType) types[0];
        System.out.println(ptt.getRawType());
        System.out.println(ptt.getOwnerType());
        System.out.println(ptt.getActualTypeArguments()[0]);
    }
}
